<!DOCTYPE html>
<html lang="zh-CN" class="h-full">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
  <title>激光位移传感器测量</title>
  <!-- Tailwind CSS via CDN -->
  <script src="https://cdn.tailwindcss.com"></script>
  <!-- Material Icons -->
  <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"/>
  <!-- Chart.js for real-time visualization -->
  <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
  <style>
    @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
    body, html {
      font-family: 'Inter', sans-serif;
      height: 100%;
      margin: 0;
      padding: 0;
    }
    .transition-all-ease-in-out {
      transition: all 0.3s ease-in-out;
    }
    .hover-lift:hover {
      transform: translateY(-4px);
    }
    .fade-in {
      opacity: 0;
      transform: translateY(10px);
      animation: fadeIn 0.6s forwards;
    }
    @keyframes fadeIn {
      to {
        opacity: 1;
        transform: translateY(0);
      }
    }
    .dark-mode-gradient {
      background: linear-gradient(to bottom right, #1e293b, #0f172a);
    }
    .light-mode-gradient {
      background: linear-gradient(to bottom right, #f8fafc, #e2e8f0);
    }
    .card-hover-effect {
      transition: box-shadow 0.3s ease, border-color 0.3s ease;
    }
    .card-hover-effect:hover {
      box-shadow: 0 10px 25px -5px rgba(59, 130, 246, 0.2), 0 8px 10px -6px rgba(59, 130, 246, 0.1);
      border-color: #60a5fa;
    }
    .realtime-gauge {
      --gauge-size: 200px;
      width: var(--gauge-size);
      height: var(--gauge-size);
      position: relative;
      margin: 0 auto;
    }
    canvas.gauge-canvas {
      display: block;
      width: 100%;
      height: 100%;
    }
    .status-dot {
      display: inline-block;
      width: 10px;
      height: 10px;
      border-radius: 50%;
      margin-right: 6px;
    }
    .status-running {
      background-color: #10b981;
    }
    .status-stopped {
      background-color: #ef4444;
    }
    .status-pending {
      background-color: #f59e0b;
    }
    .switch-toggle {
      position: relative;
      display: inline-block;
      width: 50px;
      height: 24px;
    }
    .switch-toggle input {
      opacity: 0;
      width: 0;
      height: 0;
    }
    .slider {
      position: absolute;
      cursor: pointer;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      background-color: #ccc;
      transition: .4s;
      border-radius: 24px;
    }
    .slider:before {
      position: absolute;
      content: "";
      height: 18px;
      width: 18px;
      left: 3px;
      bottom: 3px;
      background-color: white;
      transition: .4s;
      border-radius: 50%;
    }
    input:checked + .slider {
      background-color: #3b82f6;
    }
    input:checked + .slider:before {
      transform: translateX(26px);
    }
  </style>
</head>
<body class="h-full bg-gray-100 dark:bg-gray-900 text-gray-800 dark:text-gray-200 transition-all-ease-in-out">
  <!-- Theme Toggle Button -->
  <div class="fixed top-4 right-4 z-50 flex items-center space-x-2">
    <span class="text-sm">🌞</span>
    <label class="switch-toggle">
      <input type="checkbox" id="theme-toggle"/>
      <span class="slider"></span>
    </label>
    <span class="text-sm">🌙</span>
  </div>

  <!-- Main Container -->
  <div id="app" class="container mx-auto px-4 py-6 h-full flex flex-col gap-6">
    <!-- Header Section -->
    <header class="text-center fade-in">
      <h1 class="text-3xl md:text-4xl font-bold text-blue-600 dark:text-blue-400 mb-2">
        激光位移传感器测量
      </h1>
      <p class="text-gray-600 dark:text-gray-400 text-sm md:text-base">
        实时监控云台角度与距离数据，支持连续/定点双模式采集
      </p>
    </header>

    <!-- Connection & Control Panel -->
    <section class="grid grid-cols-1 md:grid-cols-3 gap-6">
      <!-- Device Connection Card -->
      <div class="bg-white dark:bg-gray-800 p-6 rounded-xl shadow-md border border-gray-200 dark:border-gray-700 card-hover-effect fade-in">
        <h2 class="text-xl font-semibold mb-4 flex items-center">
          <span class="material-icons mr-2 text-blue-500">settings_ethernet</span>
          设备连接
        </h2>
        <div class="space-y-3">
          <div>
            <label class="block text-xs font-medium text-gray-500 dark:text-gray-400 mb-1">串口端口</label>
            <input type="text" id="port-input" value="COM3" class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-blue-500 focus:outline-none bg-gray-50 dark:bg-gray-700 text-sm"/>
          </div>
          <div>
            <label class="block text-xs font-medium text-gray-500 dark:text-gray-400 mb-1">波特率</label>
            <select id="baudrate-select" class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-blue-500 focus:outline-none bg-gray-50 dark:bg-gray-700 text-sm">
              <option>9600</option>
              <option>19200</option>
              <option selected>115200</option>
            </select>
          </div>
          <div class="flex space-x-2 mt-4">
            <button id="connect-btn" class="flex-1 bg-blue-600 hover:bg-blue-700 text-white py-2 px-4 rounded-lg transition-colors text-sm font-medium hover-lift">
              连接设备
            </button>
            <button id="disconnect-btn" class="flex-1 bg-red-600 hover:bg-red-700 text-white py-2 px-4 rounded-lg transition-colors text-sm font-medium hover-lift">
              断开
            </button>
          </div>
        </div>
        <div class="mt-4 pt-4 border-t border-gray-200 dark:border-gray-700">
          <div class="flex items-center text-sm">
            <span class="status-dot status-pending" id="connection-status-dot"></span>
            <span id="connection-status-text">未连接</span>
          </div>
        </div>
      </div>

      <!-- Measurement Mode Card -->
      <div class="bg-white dark:bg-gray-800 p-6 rounded-xl shadow-md border border-gray-200 dark:border-gray-700 card-hover-effect fade-in">
        <h2 class="text-xl font-semibold mb-4 flex items-center">
          <span class="material-icons mr-2 text-blue-500">flash_on</span>
          采集模式
        </h2>
        <div class="space-y-4">
          <div>
            <label class="inline-flex items-center cursor-pointer">
              <span class="mr-3 text-sm">连续旋转</span>
              <input type="radio" name="measure-mode" value="continuous" checked class="hidden peer"/>
              <div class="w-11 h-6 bg-gray-300 peer-checked:bg-blue-600 rounded-full after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:after:translate-x-full"></div>
            </label>
            <label class="inline-flex items-center ml-6 cursor-pointer">
              <span class="mr-3 text-sm">定点采集</span>
              <input type="radio" name="measure-mode" value="fixed_angle" class="hidden peer"/>
              <div class="w-11 h-6 bg-gray-300 peer-checked:bg-blue-600 rounded-full after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:after:translate-x-full"></div>
            </label>
          </div>
          <div id="angle-step-container" class="hidden">
            <label class="block text-xs font-medium text-gray-500 dark:text-gray-400 mb-1">角度间隔 (°)</label>
            <input type="number" id="angle-step-input" min="1" max="180" value="10" class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-blue-500 focus:outline-none bg-gray-50 dark:bg-gray-700 text-sm"/>
          </div>
          <button id="set-mode-btn" class="w-full bg-indigo-600 hover:bg-indigo-700 text-white py-2 px-4 rounded-lg transition-colors text-sm font-medium hover-lift">
            应用模式设置
          </button>
        </div>
      </div>

      <!-- System Control Card -->
      <div class="bg-white dark:bg-gray-800 p-6 rounded-xl shadow-md border border-gray-200 dark:border-gray-700 card-hover-effect fade-in">
        <h2 class="text-xl font-semibold mb-4 flex items-center">
          <span class="material-icons mr-2 text-blue-500">control_camera</span>
          系统控制
        </h2>
        <div class="space-y-3">
          <button id="start-btn" class="w-full bg-green-600 hover:bg-green-700 text-white py-3 px-4 rounded-lg transition-colors font-medium hover-lift flex items-center justify-center">
            <span class="material-icons mr-2">play_arrow</span>
            开始测量
          </button>
          <button id="stop-btn" class="w-full bg-yellow-500 hover:bg-yellow-600 text-white py-3 px-4 rounded-lg transition-colors font-medium hover-lift flex items-center justify-center">
            <span class="material-icons mr-2">pause</span>
            暂停
          </button>
          <button id="reset-btn" class="w-full bg-purple-600 hover:bg-purple-700 text-white py-3 px-4 rounded-lg transition-colors font-medium hover-lift flex items-center justify-center">
            <span class="material-icons mr-2">refresh</span>
            复位归零
          </button>
          <button id="emergency-btn" class="w-full bg-red-700 hover:bg-red-800 text-white py-3 px-4 rounded-lg transition-colors font-medium hover-lift flex items-center justify-center">
            <span class="material-icons mr-2">warning</span>
            紧急停止
          </button>
        </div>
      </div>
    </section>

    <!-- Real-Time Data Display -->
    <section class="grid grid-cols-1 lg:grid-cols-2 gap-6">
      <!-- Gauge Visualization -->
      <div class="bg-white dark:bg-gray-800 p-6 rounded-xl shadow-md border border-gray-200 dark:border-gray-700 card-hover-effect fade-in">
        <h2 class="text-xl font-semibold mb-4 flex items-center">
          <span class="material-icons mr-2 text-blue-500">speed</span>
          实时测量值
        </h2>
        <div class="realtime-gauge mb-6" id="gauge-container">
          <canvas id="gauge-canvas"></canvas>
        </div>
        <div class="grid grid-cols-2 gap-4 text-center text-sm">
          <div class="bg-blue-50 dark:bg-blue-900/30 p-3 rounded-lg border border-blue-100 dark:border-blue-800">
            <p class="text-gray-500 dark:text-gray-400">当前角度</p>
            <p class="text-xl font-bold text-blue-600 dark:text-blue-400" id="display-angle">--</p>
          </div>
          <div class="bg-green-50 dark:bg-green-900/30 p-3 rounded-lg border border-green-100 dark:border-green-800">
            <p class="text-gray-500 dark:text-gray-400">测量距离</p>
            <p class="text-xl font-bold text-green-600 dark:text-green-400" id="display-distance">--</p>
          </div>
        </div>
      </div>

      <!-- Live Status Info -->
      <div class="bg-white dark:bg-gray-800 p-6 rounded-xl shadow-md border border-gray-200 dark:border-gray-700 card-hover-effect fade-in">
        <h2 class="text-xl font-semibold mb-4 flex items-center">
          <span class="material-icons mr-2 text-blue-500">info</span>
          当前状态
        </h2>
        <div class="space-y-4 text-sm">
          <div class="flex justify-between py-2 border-b border-gray-100 dark:border-gray-700">
            <span class="text-gray-600 dark:text-gray-400">系统状态：</span>
            <span id="system-status-text" class="font-medium text-gray-800 dark:text-gray-200">待机</span>
          </div>
          <div class="flex justify-between py-2 border-b border-gray-100 dark:border-gray-700">
            <span class="text-gray-600 dark:text-gray-400">运行中：</span>
            <span id="measuring-status" class="font-medium">否</span>
          </div>
          <div class="flex justify-between py-2 border-b border-gray-100 dark:border-gray-700">
            <span class="text-gray-600 dark:text-gray-400">当前传感器：</span>
            <span id="sensor-range" class="font-medium text-blue-600 dark:text-blue-400">50mm</span>
          </div>
          <div class="flex justify-between py-2 border-b border-gray-100 dark:border-gray-700">
            <span class="text-gray-600 dark:text-gray-400">累计移动距离：</span>
            <span id="total-move-distance" class="font-medium">0.0 mm</span>
          </div>
          <div class="flex justify-between py-2">
            <span class="text-gray-600 dark:text-gray-400">采集数据量：</span>
            <span id="data-count" class="font-medium">0 条</span>
          </div>
        </div>
        <div class="mt-6">
          <button id="download-data-btn" class="w-full bg-gray-600 hover:bg-gray-700 text-white py-2 px-4 rounded-lg transition-colors text-sm font-medium hover-lift flex items-center justify-center">
            <span class="material-icons mr-2">download</span>
            下载CSV数据
          </button>
        </div>
      </div>
    </section>

    <!-- Chart Visualization -->
    <section class="bg-white dark:bg-gray-800 p-6 rounded-xl shadow-md border border-gray-200 dark:border-gray-700 card-hover-effect fade-in">
      <h2 class="text-xl font-semibold mb-4 flex items-center">
        <span class="material-icons mr-2 text-blue-500">show_chart</span>
        实时趋势图
      </h2>
      <div class="h-80">
        <canvas id="chart-canvas"></canvas>
      </div>
    </section>
  </div>

  <script>
    // Initialize theme based on system preference
    const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
    document.documentElement.classList.toggle('dark', prefersDark);
    const themeToggle = document.getElementById('theme-toggle');
    themeToggle.checked = prefersDark;

    themeToggle.addEventListener('change', () => {
      const isDark = themeToggle.checked;
      document.documentElement.classList.toggle('dark', isDark);
    });

    // Show/hide angle step input based on mode selection
    const continuousRadio = document.querySelector("input[value='continuous']");
    const fixedAngleRadio = document.querySelector("input[value='fixed_angle']");
    const angleStepContainer = document.getElementById('angle-step-container');

    function updateModeInputs() {
      if (fixedAngleRadio.checked) {
        angleStepContainer.classList.remove('hidden');
      } else {
        angleStepContainer.classList.add('hidden');
      }
    }

    continuousRadio.addEventListener('change', updateModeInputs);
    fixedAngleRadio.addEventListener('change', updateModeInputs);
    updateModeInputs(); // Initial call

    // API Base URL
    const API_BASE = 'http://localhost:5000/api';

    // Elements
    const connectBtn = document.getElementById('connect-btn');
    const disconnectBtn = document.getElementById('disconnect-btn');
    const startBtn = document.getElementById('start-btn');
    const stopBtn = document.getElementById('stop-btn');
    const resetBtn = document.getElementById('reset-btn');
    const emergencyBtn = document.getElementById('emergency-btn');
    const setModeBtn = document.getElementById('set-mode-btn');
    const downloadDataBtn = document.getElementById('download-data-btn');

    const connectionStatusDot = document.getElementById('connection-status-dot');
    const connectionStatusText = document.getElementById('connection-status-text');
    const systemStatusText = document.getElementById('system-status-text');
    const measuringStatus = document.getElementById('measuring-status');
    const displayAngle = document.getElementById('display-angle');
    const displayDistance = document.getElementById('display-distance');
    const sensorRange = document.getElementById('sensor-range');
    const totalMoveDistance = document.getElementById('total-move-distance');
    const dataCount = document.getElementById('data-count');

    // Status polling
    let pollInterval = null;

    async function fetchStatus() {
      try {
        const res = await fetch(`${API_BASE}/status`);
        const data = await res.json();
        updateUIWithStatus(data);
      } catch (err) {
        console.error('获取状态失败:', err);
        connectionStatusText.textContent = '连接异常';
        connectionStatusDot.className = 'status-dot status-stopped';
      }
    }

    function updateUIWithStatus(data) {
      const { system_status, measuring, current_angle, current_distance, total_move_distance, current_sensor_range, data_count } = data;

      connectionStatusText.textContent = system_status;
      connectionStatusDot.className = `status-dot ${system_status === '已连接' || measuring ? 'status-running' : system_status === '已断开连接' ? 'status-stopped' : 'status-pending'}`;
      systemStatusText.textContent = system_status;
      measuringStatus.textContent = measuring ? '是' : '否';
      displayAngle.textContent = current_angle !== null ? `${current_angle.toFixed(2)}°` : '--';
      displayDistance.textContent = current_distance !== null ? `${current_distance.toFixed(5)} mm` : '--';
      sensorRange.textContent = current_sensor_range;
      totalMoveDistance.textContent = `${total_move_distance.toFixed(1)} mm`;
      dataCount.textContent = `${data_count} 条`;

      // Update gauge and chart
      updateGauge(current_angle !== null ? current_angle % 360 : 0);
      if (current_angle !== null && current_distance !== null) {
        updateChart(current_angle % 360, current_distance);
      }
    }

    // Connect device
    connectBtn.addEventListener('click', async () => {
      const port = document.getElementById('port-input').value;
      const baudrate = parseInt(document.getElementById('baudrate-select').value);

      try {
        const res = await fetch(`${API_BASE}/connect`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ port, baudrate })
        });
        const result = await res.json();

        if (result.status === 'success') {
          alert('设备连接成功！');
          if (!pollInterval) {
            pollInterval = setInterval(fetchStatus, 500);
          }
        } else {
          alert(`连接失败: ${result.message}`);
        }
      } catch (err) {
        alert(`连接请求失败: ${err.message}`);
      }
    });

    // Disconnect device
    disconnectBtn.addEventListener('click', async () => {
      try {
        const res = await fetch(`${API_BASE}/disconnect`, { method: 'POST' });
        const result = await res.json();
        if (result.status === 'success') {
          clearInterval(pollInterval);
          pollInterval = null;
          alert('设备已断开');
          updateUIWithStatus({
            system_status: "已断开连接",
            measuring: false,
            current_angle: null,
            current_distance: null,
            total_move_distance: 0,
            current_sensor_range: "50mm",
            data_count: 0
          });
        } else {
          alert(`断开失败: ${result.message}`);
        }
      } catch (err) {
        alert(`断开请求失败: ${err.message}`);
      }
    });

    // Set measurement mode
    setModeBtn.addEventListener('click', async () => {
      const measureMode = document.querySelector("input[name='measure-mode']:checked").value;
      const angleStepInput = document.getElementById('angle-step-input');
      let payload = { measure_mode: measureMode };

      if (measureMode === 'fixed_angle') {
        const angleStep = parseInt(angleStepInput.value);
        if (isNaN(angleStep) || angleStep < 1 || angleStep > 180) {
          alert('请设置1-180之间的有效角度间隔');
          return;
        }
        payload.angle_step = angleStep;
      }

      try {
        const res = await fetch(`${API_BASE}/set-mode`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify(payload)
        });
        const result = await res.json();
        if (result.status === 'success') {
          alert(`采集模式已设置为：${measureMode === 'continuous' ? '连续旋转' : '定点采集'}`);
        } else {
          alert(`设置失败: ${result.message}`);
        }
      } catch (err) {
        alert(`请求失败: ${err.message}`);
      }
    });

    // Start measurement
    startBtn.addEventListener('click', async () => {
      try {
        const res = await fetch(`${API_BASE}/start`, { method: 'POST' });
        const result = await res.json();
        if (result.status === 'success') {
          alert('测量已启动');
        } else {
          alert(`启动失败: ${result.message}`);
        }
      } catch (err) {
        alert(`启动请求失败: ${err.message}`);
      }
    });

    // Stop measurement
    stopBtn.addEventListener('click', async () => {
      try {
        const res = await fetch(`${API_BASE}/stop`, { method: 'POST' });
        const result = await res.json();
        if (result.status === 'success') {
          alert('测量已暂停');
        } else {
          alert(`停止失败: ${result.message}`);
        }
      } catch (err) {
        alert(`停止请求失败: ${err.message}`);
      }
    });

    // Reset system
    resetBtn.addEventListener('click', async () => {
      try {
        const res = await fetch(`${API_BASE}/reset`, { method: 'POST' });
        const result = await res.json();
        if (result.status === 'success') {
          alert('系统正在复位，请等待...');
        } else {
          alert(`复位失败: ${result.message}`);
        }
      } catch (err) {
        alert(`复位请求失败: ${err.message}`);
      }
    });

    // Emergency stop
    emergencyBtn.addEventListener('click', async () => {
      if (!confirm('确定要执行紧急停止吗？此操作将立即中断所有运动！')) return;

      try {
        const res = await fetch(`${API_BASE}/emergency`, { method: 'POST' });
        const result = await res.json();
        if (result.status === 'success') {
          alert('已执行紧急停止');
        } else {
          alert(`紧急停止失败: ${result.message}`);
        }
      } catch (err) {
        alert(`紧急停止请求失败: ${err.message}`);
      }
    });

    // Download data
    downloadDataBtn.addEventListener('click', () => {
      const link = document.createElement('a');
      link.href = `${API_BASE}/download-data`;
      link.setAttribute('target', '_blank');
      document.body.appendChild(link);
      link.click();
      document.body.removeChild(link);
    });

    // Real-time Gauge using Canvas
    const gaugeCanvas = document.getElementById('gauge-canvas');
    const gaugeCtx = gaugeCanvas.getContext('2d');
    let gaugeAngle = 0;

    function drawGauge() {
      const size = gaugeCanvas.parentElement.offsetWidth;
      gaugeCanvas.width = size;
      gaugeCanvas.height = size;

      gaugeCtx.clearRect(0, 0, size, size);

      // Background circle
      gaugeCtx.beginPath();
      gaugeCtx.arc(size / 2, size / 2, size / 2 - 10, 0, 2 * Math.PI);
      gaugeCtx.strokeStyle = '#e2e8f0';
      gaugeCtx.lineWidth = 16;
      gaugeCtx.stroke();

      // Progress arc
      const startAngle = -Math.PI / 2;
      const endAngle = startAngle + (gaugeAngle / 360) * 2 * Math.PI;
      gaugeCtx.beginPath();
      gaugeCtx.arc(size / 2, size / 2, size / 2 - 10, startAngle, endAngle);
      gaugeCtx.strokeStyle = '#3b82f6';
      gaugeCtx.lineWidth = 16;
      gaugeCtx.lineCap = 'round';
      gaugeCtx.stroke();

      // Center text
      gaugeCtx.font = 'bold 24px Inter';
      gaugeCtx.fillStyle = '#1e293b';
      gaugeCtx.textAlign = 'center';
      gaugeCtx.fillText(Math.round(gaugeAngle) + '°', size / 2, size / 2 + 10);
    }

    function updateGauge(angle) {
      gaugeAngle = angle;
      drawGauge();
    }

    // Initialize gauge
    drawGauge();

    // Responsive resize
    window.addEventListener('resize', () => {
      drawGauge();
      chart.resize();
    });

    // Real-time Chart using Chart.js
    const chartCtx = document.getElementById('chart-canvas').getContext('2d');
    const chart = new Chart(chartCtx, {
      type: 'line',
      data: {
        labels: [],
        datasets: [{
          label: '测量距离 (mm)',
          data: [],
          borderColor: '#3b82f6',
          backgroundColor: 'rgba(59, 130, 246, 0.1)',
          borderWidth: 2,
          pointRadius: 2,
          fill: true,
          tension: 0.3
        }]
      },
      options: {
        responsive: true,
        maintainAspectRatio: false,
        plugins: {
          legend: {
            display: true,
            position: 'top'
          },
          tooltip: {
            mode: 'index',
            intersect: false
          }
        },
        scales: {
          x: {
            title: {
              display: true,
              text: '云台角度 (°)'
            }
          },
          y: {
            title: {
              display: true,
              text: '距离 (mm)'
            }
          }
        },
        interaction: {
          mode: 'nearest',
          axis: 'x',
          intersect: false
        }
      }
    });

    function updateChart(angle, distance) {
      const labels = chart.data.labels;
      const data = chart.data.datasets[0].data;

      // Keep last 100 points
      if (labels.length >= 100) {
        labels.shift();
        data.shift();
      }

      labels.push(angle.toFixed(1));
      data.push(distance);

      chart.update();
    }

    // Auto connect on load if desired
    // Uncomment below to auto-fetch status every 500ms after page loads
    // window.addEventListener('load', () => {
    //   pollInterval = setInterval(fetchStatus, 500);
    // });
  </script>
</body>
</html>